package com.explment.lens.utils.rsa;

import javax.crypto.*;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
import java.security.*;
import java.util.Base64;

/**
 * RSA加密由于性能限制和块大小限制，确实只适合加密小数据量（如对称密钥），而对于大数据加密，推荐使用对称加密+RSA密钥交换的混合方案
 *
 * 1.使用RSA加密对称密钥（如AES密钥）
 *
 * 2.使用对称加密算法（如AES）加密实际数据
 *
 * 3.接收方先使用RSA解密出对称密钥，再用对称密钥解密数据
 */
public class RsaAndAesEncryUtil {
    private static final String RSA_ALGORITHM = "RSA";
    private static final String AES_ALGORITHM = "AES/CBC/PKCS5Padding";
    private static final int AES_KEY_SIZE = 256; // AES-256
    private static final int IV_LENGTH = 16; // AES块大小

    private final RSAUtils rsaUtils;

    public RsaAndAesEncryUtil() {
        this.rsaUtils = new RSAUtils();
    }

    /**
     * 加载RSA密钥对
     */
    public void loadKeyPair(String publicKeyPath, String privateKeyPath) throws Exception {
        rsaUtils.loadKeyPair(publicKeyPath, privateKeyPath);
    }

    /**
     * 生成并保存RSA密钥对
     */
    public void generateAndSaveKeyPair(String publicKeyPath, String privateKeyPath) throws Exception {
        rsaUtils.generateAndSaveKeyPair(publicKeyPath, privateKeyPath);
    }

    /**
     * 混合加密：使用RSA加密AES密钥，用AES加密数据
     * @return 包含加密后的AES密钥和加密数据的JSON字符串
     */
    public String hybridEncrypt(String data) throws Exception {
        try {
            // 1. 生成随机AES密钥和IV
            KeyGenerator keyGen = KeyGenerator.getInstance("AES");
            keyGen.init(AES_KEY_SIZE);
            SecretKey aesKey = keyGen.generateKey();
            byte[] iv = new byte[IV_LENGTH];
            SecureRandom random = new SecureRandom();
            random.nextBytes(iv);
            IvParameterSpec ivSpec = new IvParameterSpec(iv);

            // 2. 用AES加密实际数据
            Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM);
            aesCipher.init(Cipher.ENCRYPT_MODE, aesKey, ivSpec);
            byte[] encryptedData = aesCipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

            // 3. 用RSA加密AES密钥
            byte[] encryptedAesKey = rsaUtils.encryptWithPublicKey(aesKey.getEncoded());

            // 4. 返回组合结果（实际应用中建议用JSON等结构化格式）
            return String.format("{\"encryptedKey\":\"%s\",\"iv\":\"%s\",\"encryptedData\":\"%s\"}",
                    Base64.getEncoder().encodeToString(encryptedAesKey),
                    Base64.getEncoder().encodeToString(iv),
                    Base64.getEncoder().encodeToString(encryptedData));

        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("AES algorithm not available", e);
        }
    }

    /**
     * 混合解密：先用RSA解密AES密钥，再用AES解密数据
     */
    public String hybridDecrypt(String encryptedPackage) throws Exception {
        try {
            // 1. 解析加密包（实际应用中建议用JSON解析库）
            // 这里简化处理，实际格式应为结构化数据
            String[] parts = encryptedPackage.split("\"");
            byte[] encryptedKey = Base64.getDecoder().decode(parts[3]);
            byte[] iv = Base64.getDecoder().decode(parts[7]);
            byte[] encryptedData = Base64.getDecoder().decode(parts[11]);

            // 2. 用RSA解密AES密钥
            byte[] aesKeyBytes = rsaUtils.decryptWithPrivateKey(encryptedKey);
            SecretKey aesKey = new SecretKeySpec(aesKeyBytes, "AES");
            IvParameterSpec ivSpec = new IvParameterSpec(iv);

            // 3. 用AES解密数据
            Cipher aesCipher = Cipher.getInstance(AES_ALGORITHM);
            aesCipher.init(Cipher.DECRYPT_MODE, aesKey, ivSpec);
            byte[] decryptedData = aesCipher.doFinal(encryptedData);

            return new String(decryptedData, StandardCharsets.UTF_8);

        } catch (Exception e) {
            throw new RuntimeException("Decryption failed", e);
        }
    }

    /*public static void main(String[] args) {
        RsaAndAesEncryUtil hybridUtil = new RsaAndAesEncryUtil();

        try {
            // 1. 生成或加载密钥对
            hybridUtil.generateAndSaveKeyPair(
                    "src/main/resources/keys/public.key",
                    "src/main/resources/keys/private.key"
            );

            // 2. 准备大数据（示例中使用字符串，实际可能是文件内容等）
            StringBuilder largeData = new StringBuilder();
            for (int i = 0; i < 1000; i++) {
                largeData.append("这是大数据的一部分，索引: ").append(i).append("\n");
            }

            // 3. 混合加密
            System.out.println("开始混合加密...");
            String encryptedPackage = hybridUtil.hybridEncrypt(largeData.toString());
            System.out.println("加密完成，加密包大小: " + encryptedPackage.length() + " 字符");

            // 4. 混合解密
            System.out.println("开始混合解密...");
            String decryptedData = hybridUtil.hybridDecrypt(encryptedPackage);

            // 5. 验证数据一致性
            System.out.println("原始数据长度: " + largeData.length());
            System.out.println("解密数据长度: " + decryptedData.length());
            System.out.println("数据一致性: " + largeData.toString().equals(decryptedData));

        } catch (Exception e) {
            System.err.println("混合加密过程出错: " + e.getMessage());
            e.printStackTrace();
        }
    }*/
}
